﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Domains;

namespace Lambda
{
    public static class Utilities
    {
        public static Func<Domain, Func<Domain,Domain>> result =
            new Func<Domain, Func<Domain, Domain>>(v => s => new DomainPair(v,s));

        public static Func<Domain, Domain> donothing = new Func<Domain, Domain>(s => s);

        public static Func<Domain, Func<Domain, Domain>> checkNum =
            new Func<Domain, Func<Domain, Domain>>(v => s =>
                v is Num ? (Domain)(new DomainPair(v, s)) : (Domain)(new Error()));

        public static Func<Domain, Func<Domain, Domain>> checkBool =
            new Func<Domain, Func<Domain, Domain>>(v => s =>
                v is Bool ? (Domain)(new DomainPair(v, s)) : (Domain)(new Error()));

        public static Func<State, Ide, Domain> IdentifierExpression = 
            new Func<State, Ide, Domain>((State s, Ide i) => Unbound((State)s, (Ide)i) ?
                (Domain)(new Error()) :
                (Domain)(new DomainPair(s.Memory.Value[getIdeByText(s, i)], s)));

        public static Func<State, Domain> ReadExpression =
            new Func<State, Domain>( s => Null(s) ? (Domain)(new Error()) : (Domain)(new DomainPair(Input.head(s.Input), s)));

        public static Func<State, Value, Domain> OutputCommand= new  Func<State, Value, Domain>(
            (s,v) => { 
                s.Output.Value.Add(v);
                return s;
            });
        public static Func<State, Ide, Value, Domain> bindingCommand = new Func<State, Ide, Value, Domain>(
            (s, i, v) =>
                {
                    if (Unbound(s, i))
                        s.Memory.Value.Add(i, v);
                    else
                        s.Memory.Value[getIdeByText(s, i)] = v;
                    return s;
                });


        private static bool Unbound(State s, Ide i)
        {
            return s.Memory.Value.Count(elem => elem.Key.Value == i.Value) == 0;
        }

        private static bool Null(State s)
        {
            return s.Input.Value.Count == 0;
        }
        private static Ide getIdeByText(State s, Ide i)
        {
            return s.Memory.Value.Single(elem => elem.Key.Value == i.Value).Key;
        }

    }
}
